package com.cl.service.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.cl.dao.TokenDao;
import com.cl.entity.TokenEntity;
import com.cl.service.TokenService;
import com.cl.utils.CommonUtil;
import com.cl.utils.PageUtils;
import com.cl.utils.Query;

/**
 * Token服务实现类
 * 处理用户令牌的生成、验证和管理
 */
@Service("tokenService")
public class TokenServiceImpl extends ServiceImpl<TokenDao, TokenEntity> implements TokenService {
    
    private static final Logger logger = LoggerFactory.getLogger(TokenServiceImpl.class);
    private static final int TOKEN_LENGTH = 32;
    private static final int TOKEN_EXPIRATION_HOURS = 1;

    /**
     * 基本分页查询
     * @param params 查询参数
     * @return 分页结果
     * @throws RuntimeException 查询失败时抛出
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        validateParams(params);
        logger.debug("执行基本分页查询");
        
        try {
            Page<TokenEntity> page = this.selectPage(
                    new Query<TokenEntity>(params).getPage(),
                    new EntityWrapper<TokenEntity>()
            );
            return new PageUtils(page);
        } catch (Exception e) {
            logger.error("分页查询失败", e);
            throw new RuntimeException("查询数据失败", e);
        }
    }

    /**
     * 查询视图列表
     * @param wrapper 查询条件包装器
     * @return 视图列表
     * @throws RuntimeException 查询失败时抛出
     */
    @Override
    public List<TokenEntity> selectListView(Wrapper<TokenEntity> wrapper) {
        validateWrapper(wrapper);
        logger.debug("查询视图列表");
        
        try {
            return baseMapper.selectListView(wrapper);
        } catch (Exception e) {
            logger.error("查询视图列表失败", e);
            throw new RuntimeException("查询视图列表失败", e);
        }
    }

    /**
     * 条件分页查询
     * @param params 查询参数
     * @param wrapper 查询条件包装器
     * @return 分页结果
     * @throws RuntimeException 查询失败时抛出
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params, Wrapper<TokenEntity> wrapper) {
        validateParams(params);
        validateWrapper(wrapper);
        logger.debug("执行条件分页查询");
        
        try {
            Page<TokenEntity> page = new Query<TokenEntity>(params).getPage();
            page.setRecords(baseMapper.selectListView(page, wrapper));
            return new PageUtils(page);
        } catch (Exception e) {
            logger.error("条件分页查询失败", e);
            throw new RuntimeException("条件查询数据失败", e);
        }
    }

    /**
     * 生成用户令牌
     * @param userId 用户ID
     * @param username 用户名
     * @param tableName 表名
     * @param role 角色
     * @return 生成的令牌字符串
     * @throws IllegalArgumentException 如果参数无效
     * @throws RuntimeException 如果令牌生成失败
     */
    @Override
    public String generateToken(Long userId, String username, String tableName, String role) {
        validateTokenParams(userId, username, role);
        logger.debug("为用户{}生成令牌，角色：{}", username, role);
        
        try {
            TokenEntity tokenEntity = this.selectOne(
                    new EntityWrapper<TokenEntity>().eq("userid", userId).eq("role", role)
            );

            String token = CommonUtil.getRandomString(TOKEN_LENGTH);
            Date expirationTime = calculateExpirationTime();

            if (tokenEntity != null) {
                logger.debug("更新用户{}的现有令牌", username);
                updateExistingToken(tokenEntity, token, expirationTime);
            } else {
                logger.debug("为用户{}创建新令牌", username);
                createNewToken(userId, username, tableName, role, token, expirationTime);
            }

            return token;
        } catch (IllegalArgumentException e) {
            throw e;
        } catch (Exception e) {
            logger.error("令牌生成失败", e);
            throw new RuntimeException("令牌生成失败", e);
        }
    }

    /**
     * 通过令牌获取令牌实体
     * @param token 令牌字符串
     * @return 令牌实体，如果令牌无效或已过期则返回null
     * @throws RuntimeException 如果查询失败
     */
    @Override
    public TokenEntity getTokenEntity(String token) {
        if (token == null || token.isEmpty()) {
            logger.warn("尝试获取空令牌");
            return null;
        }
        
        logger.debug("获取令牌实体");
        try {
            TokenEntity tokenEntity = this.selectOne(new EntityWrapper<TokenEntity>().eq("token", token));
            
            if (isTokenExpired(tokenEntity)) {
                logger.debug("令牌已过期或无效");
                return null;
            }
            
            return tokenEntity;
        } catch (Exception e) {
            logger.error("获取令牌实体失败", e);
            throw new RuntimeException("获取令牌实体失败", e);
        }
    }

    /**
     * 验证令牌参数有效性
     * @param userId 用户ID
     * @param username 用户名
     * @param role 角色
     * @throws IllegalArgumentException 如果参数无效
     */
    private void validateTokenParams(Long userId, String username, String role) {
        Objects.requireNonNull(userId, "用户ID不能为空");
        Objects.requireNonNull(username, "用户名不能为空");
        Objects.requireNonNull(role, "角色不能为空");
        
        if (username.trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空字符串");
        }
        
        if (role.trim().isEmpty()) {
            throw new IllegalArgumentException("角色不能为空字符串");
        }
    }

    /**
     * 计算令牌过期时间
     * @return 过期时间的Date对象
     */
    private Date calculateExpirationTime() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.HOUR_OF_DAY, TOKEN_EXPIRATION_HOURS);
        return cal.getTime();
    }

    /**
     * 更新现有令牌
     * @param tokenEntity 现有令牌实体
     * @param token 新令牌值
     * @param expirationTime 过期时间
     */
    private void updateExistingToken(TokenEntity tokenEntity, String token, Date expirationTime) {
        tokenEntity.setToken(token);
        tokenEntity.setExpiratedtime(expirationTime);
        try {
            this.updateById(tokenEntity);
        } catch (Exception e) {
            logger.error("更新令牌失败: {}", tokenEntity.getUserid(), e);
            throw new RuntimeException("更新令牌失败", e);
        }
    }

    /**
     * 创建新令牌
     * @param userId 用户ID
     * @param username 用户名
     * @param tableName 表名
     * @param role 角色
     * @param token 令牌值
     * @param expirationTime 过期时间
     */
    private void createNewToken(Long userId, String username, String tableName, String role, String token, Date expirationTime) {
        TokenEntity newTokenEntity = new TokenEntity(userId, username, tableName, role, token, expirationTime);
        try {
            this.insert(newTokenEntity);
        } catch (Exception e) {
            logger.error("创建令牌失败: {}", userId, e);
            throw new RuntimeException("创建令牌失败", e);
        }
    }

    /**
     * 检查令牌是否过期
     * @param tokenEntity 令牌实体
     * @return 如果令牌过期或无效则返回true，否则返回false
     */
    private boolean isTokenExpired(TokenEntity tokenEntity) {
        return tokenEntity == null || tokenEntity.getExpiratedtime().getTime() < new Date().getTime();
    }
    
    /**
     * 校验查询参数
     * @param params 查询参数
     * @throws IllegalArgumentException 如果参数为空或无效
     */
    private void validateParams(Map<String, Object> params) {
        if (params == null || params.isEmpty()) {
            logger.warn("查询参数为空");
            throw new IllegalArgumentException("参数不能为空");
        }
    }
    
    /**
     * 校验查询条件包装器
     * @param wrapper 查询条件包装器
     * @throws IllegalArgumentException 如果包装器为null
     */
    private void validateWrapper(Wrapper<TokenEntity> wrapper) {
        Objects.requireNonNull(wrapper, "查询条件不能为空");
    }
}